#include <stdlib.h>
#include "Arbre.h"
#include "Symbole.h"
#include "SymboleValue.h"

////////////////////////////////////////////////////////////////////////////////
// NoeudSeqInst
////////////////////////////////////////////////////////////////////////////////

        NoeudSeqInst::NoeudSeqInst() : tabInst() {}
        ////////////////////////////////////////////////////////////////////////
        int NoeudSeqInst::getValeur() {
                int valeur=0;
                for (unsigned int i=0; i<tabInst.size(); i++)
                        valeur = tabInst[i]->getValeur();  // on evalue chaque instruction de la séquence
                return valeur; // par convention, resultat = valeur de la derniere instruction
        }
        ////////////////////////////////////////////////////////////////////////
        void NoeudSeqInst::afficher(unsigned short indentation) {
                Noeud::afficher(indentation);
                cout << "Noeud - Sequence de " << tabInst.size() << " instruction(s)" << endl;
                for (unsigned int i=0; i<tabInst.size(); i++)
                        tabInst[i]->afficher(indentation+1); // on affiche les fils en augmentant l'indentation
        }
        ////////////////////////////////////////////////////////////////////////
        void NoeudSeqInst::ajouteInstruction(Noeud* instruction) {
                tabInst.push_back(instruction);
        }

////////////////////////////////////////////////////////////////////////////////
// NoeudAffectation
////////////////////////////////////////////////////////////////////////////////

        NoeudAffectation::NoeudAffectation(Noeud* variable, Noeud* expression) {
                this->variable=variable;
                this->expression=expression;
        }
        ////////////////////////////////////////////////////////////////////////
        int NoeudAffectation::getValeur() {
                int valeur = expression->getValeur(); // on évalue l'expression
                ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
                return valeur; // par convention, une affectation a pour valeur la valeur affectée
         }
        ////////////////////////////////////////////////////////////////////////
        void NoeudAffectation::afficher(unsigned short indentation) {
                Noeud::afficher(indentation);
                cout << "Noeud - Affectation" << endl;
                variable->afficher(indentation+1);   // on affiche variable et expression
                expression->afficher(indentation+1); // en augmentant l'indentation
        }

////////////////////////////////////////////////////////////////////////////////
// NoeudOperateurBinaire
////////////////////////////////////////////////////////////////////////////////

        NoeudOperateurBinaire::NoeudOperateurBinaire (Symbole operateur, Noeud* operandeGauche, Noeud* operandeDroit) {
                this->operateur=operateur;
                this->operandeGauche=operandeGauche;
                this->operandeDroit=operandeDroit;
        }
        ////////////////////////////////////////////////////////////////////////
        int NoeudOperateurBinaire::getValeur() { 
                int valeur=0;
                int og=operandeGauche->getValeur();
                int od=operandeDroit->getValeur();
                if      (this->operateur=="+") valeur = og+od; 
                else if (this->operateur=="-") valeur = og-od;
                else if (this->operateur=="*") valeur = og*od;
                else if (this->operateur=="ou") valeur = og||od;
                else if (this->operateur=="et") valeur = og&&od;
                else if (this->operateur=="==") valeur = og==od;
                else if (this->operateur=="!=") valeur = og!=od;
                else if (this->operateur=="<=") valeur = og<=od;
                else if (this->operateur==">=") valeur = og>=od;
                else if (this->operateur=="<") valeur = og<od;
                else if (this->operateur==">") valeur = og>od;
                else  // this->operateur=="/"
                        if (od!=0)
                                valeur = og/od;
                        else {
                	  	cout << "Erreur pendant l'interpretation : division par zero" << endl;
       	  	exit(0); // plus tard on levera une exception
                }
                return valeur;
        }
        ////////////////////////////////////////////////////////////////////////
        void NoeudOperateurBinaire::afficher(unsigned short indentation) {
                Noeud::afficher(indentation);
                cout << "Noeud - Operateur Binaire \"" << this->operateur.getChaine() << "\" applique a : " << endl;
                operandeGauche->afficher(indentation+1);  // on affiche fils gauche et fils droit
                operandeDroit->afficher(indentation+1);   // en augmentant l'indentation
        }

////////////////////////////////////////////////////////////////////////////////
// NoeudInstRepeter
////////////////////////////////////////////////////////////////////////////////

        NoeudInstRepeter::NoeudInstRepeter(Noeud* expr, Noeud* si) {
        this->seqInst=si;
        this->expression=expr;
        }
        ////////////////////////////////////////////////////////////////////////
        int NoeudInstRepeter::getValeur() {
    do {
        seqInst->getValeur();
    }
    while (expression->getValeur()==0);
    
    return 0;
;}

        ////////////////////////////////////////////////////////////////////////
        void NoeudInstRepeter::afficher(unsigned short indentation) {
                Noeud::afficher(indentation);
                cout << "Noeud - InstRepeter" << endl;
                seqInst->afficher(indentation+1);  // on affiche fils gauche et fils droit
                expression->afficher(indentation+1);   // en augmentant l'indentation
        }
        
////////////////////////////////////////////////////////////////////////////////
// NoeudInstTq
////////////////////////////////////////////////////////////////////////////////

NoeudInstTq::NoeudInstTq (Noeud* expr, Noeud* si) {
        this->seqInst=si;
        this->expression=expr;
}
        
////////////////////////////////////////////////////////////////////////////////
int NoeudInstTq::getValeur() {
      
    while (expression->getValeur()==1)
    {
        seqInst->getValeur();
    }
    return 0;
}

////////////////////////////////////////////////////////////////////////////////
void NoeudInstTq::afficher(unsigned short indentation) {
    
  Noeud::afficher(indentation);
  cout << "Noeud - InstTantQue" << endl;
  seqInst->afficher(indentation+1);  // on affiche fils gauche et fils droit
  expression->afficher(indentation+1);   // en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////
// NoeudInstPour
////////////////////////////////////////////////////////////////////////////////

NoeudInstPour::NoeudInstPour (Noeud* init,Noeud* expr,Noeud* incr,Noeud* si) {
        this->initialisation=init;
        this->expression=expr;
        this->incrementation=incr;
        this->seqInst=si;
}
////////////////////////////////////////////////////////////////////////////////
int NoeudInstPour::getValeur() {
          
    for (initialisation->getValeur();expression->getValeur()==1;incrementation->getValeur())
    {
        seqInst->getValeur();
    }
    return 0;
}

////////////////////////////////////////////////////////////////////////////////
void NoeudInstPour::afficher(unsigned short indentation) {
    
  Noeud::afficher(indentation);
  cout << "Noeud - InstPour" << endl;
  initialisation->afficher(indentation+1);
  expression->afficher(indentation+1);   // en augmentant l'indentation
  incrementation->afficher(indentation+1);
  seqInst->afficher(indentation+1);  

}


////////////////////////////////////////////////////////////////////////////////
// NoeudInstLire
////////////////////////////////////////////////////////////////////////////////

NoeudInstLire::NoeudInstLire (Noeud* var) {
        this->variable=var;

}
////////////////////////////////////////////////////////////////////////////////

int NoeudInstLire::getValeur() {

    int valeur;
          
        cout << "Entrez une valeur pour ";
        variable->afficher();
        
                cin >> valeur ;
        ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
  
  return 0;
}

////////////////////////////////////////////////////////////////////////////////
void NoeudInstLire::afficher(unsigned short indentation) {
    
  Noeud::afficher(indentation);
  cout << "Noeud - InstLire" << endl;
  variable->afficher(indentation+1);
}
